package com.lovergreen.controller;

import com.lovergreen.mail.service.EmailService;
import com.lovergreen.person.model.Person;
import com.lovergreen.person.model.PersonRole;
import com.lovergreen.person.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.RememberMeAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.mail.MessagingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;


@Controller
public class MainController {
	@Autowired PersonService personService;
	@Autowired EmailService emailService;

	@RequestMapping(value = { "/", "/welcome**" }, method = {RequestMethod.GET, RequestMethod.HEAD})
	public ModelAndView defaultPage() {

		ModelAndView model = new ModelAndView();
		model.addObject("title", "Lovergreen Security Remember Me");
		model.addObject("message", "This is default page!");
		model.setViewName("hello");
		return model;

	}
	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public String add(Model model) {
		model.addAttribute("person", new Person());
		return "addperson";
	}


	@RequestMapping(value = "/admin**", method = RequestMethod.GET)
	public ModelAndView adminPage() {
		ModelAndView model = new ModelAndView();
		model.addObject("title", "Lovergreen Security Remember Me");
		model.addObject("message", "This page is for ROLE_ADMIN only!");
		model.setViewName("admin");
		return model;
	}
	@RequestMapping(value = "/save", method = RequestMethod.POST)
	public String save(
		@RequestParam("firstname") final String firstname,
		@RequestParam("lastname") final String lastname,
		@RequestParam("email") final String email, final Locale locale,
		@Valid @ModelAttribute("person") Person person, BindingResult br, PersonRole personRole, Model model) throws MessagingException {
		if (br.hasErrors()) {
			return "addperson";
		} else {
			String confirmkey = createConfirmKey();
			person.setActive(false);
			person.setConfirmkey(confirmkey);
			personRole.setRole("ROLE_ADMIN");
			personRole.setEmail(person.getEmail());
			person.setPersonRole(personRole);
			personService.addPerson(person);
			this.emailService.sendRegisterConfirmationMail(firstname, lastname, email, confirmkey, locale);
			return "redirect:list";
		}
	}

	public String createConfirmKey(){
		Long keypart1 = System.currentTimeMillis();
		String keypart2 = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date());
		String combination = keypart1+keypart2;
		String reversedkey = new StringBuffer(combination).reverse().toString();
		return reversedkey;
	}

	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String update(
			@RequestParam("firstname") final String firstname,
			@RequestParam("lastname") final String lastname,
			@RequestParam("email") final String email, final Locale locale,
			@ModelAttribute("person") Person person, BindingResult br, Model model) throws MessagingException {
		if (br.hasErrors()) { return "updateperson"; }
		personService.updatePerson(person);
		return "redirect:list";
	}
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public String list(Model model) {
		List personlist = personService.listPerson();
		model.addAttribute("personlist", personlist);
		return "listperson";
	}
	@RequestMapping(value = "/delete/{email:.+}", method = RequestMethod.GET)
	public String delete(@PathVariable String email) {
		personService.deletePerson(email);
		return "redirect:/list";
	}

	@RequestMapping(value = "/update/{email:.+}", method = RequestMethod.GET)
	public String update(@PathVariable String email, Model model) {
		model.addAttribute("person", personService.getPerson(email));
		return "updateperson";
	}
	@RequestMapping(value = "/confirm/{confirmkey}", method = RequestMethod.GET)
	public String confirmPerson(@PathVariable String confirmkey, Person person, Model model) {
		person = personService.getPersonByUid(confirmkey);
		if (!person.getActive()) {
			person.setActive(true);
			personService.updatePerson(person);
			return "redirect:/list";
		}else{
			return "redirect:/list";
		}
	}
	/**
	 * This update page is for user login with password only.
	 * If user is logjn via remember me cookie, send login to ask for password again.
	 * To avoid stolen remember me cookie to update anything
	 */
	@RequestMapping(value = "/admin/update**", method = RequestMethod.GET)
	public ModelAndView updatePage(HttpServletRequest request) {

		ModelAndView model = new ModelAndView();

		if (isRememberMeAuthenticated()) {
			//send login for update
			setRememberMeTargetUrlToSession(request);
			model.addObject("loginUpdate", true);
			model.setViewName("/login");

		} else {
			model.setViewName("updateperson");
		}

		return model;

	}

	/**
	 * both "normal login" and "login for update" shared this form.
	 *
	 */
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public ModelAndView login(@RequestParam(value = "error", required = false) String error,
			@RequestParam(value = "logout", required = false) String logout, HttpServletRequest request) {

		ModelAndView model = new ModelAndView();
		if (error != null) {
			model.addObject("error", "Invalid username and password!");

			//login form for update, if login error, get the targetUrl from session again.
			String targetUrl = getRememberMeTargetUrlFromSession(request);
			System.out.println(targetUrl);
			if(StringUtils.hasText(targetUrl)){
				model.addObject("targetUrl", targetUrl);
				model.addObject("loginUpdate", true);
			}

		}

		if (logout != null) {
			model.addObject("msg", "You've been logged out successfully.");
		}
		model.setViewName("login");

		return model;

	}

	/**
	 * If the login in from remember me cookie, refer
	 * org.springframework.security.authentication.AuthenticationTrustResolverImpl
	 */
	private boolean isRememberMeAuthenticated() {

		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			return false;
		}

		return RememberMeAuthenticationToken.class.isAssignableFrom(authentication.getClass());
	}

	/**
	 * save targetURL in session
	 */
	private void setRememberMeTargetUrlToSession(HttpServletRequest request){
		HttpSession session = request.getSession(false);
		if(session!=null){
			session.setAttribute("targetUrl", "/admin/update");
		}
	}

	/**
	 * get targetURL from session
	 */
	private String getRememberMeTargetUrlFromSession(HttpServletRequest request){
		String targetUrl = "";
		HttpSession session = request.getSession(false);
		if(session!=null){
			targetUrl = session.getAttribute("targetUrl")==null?"":session.getAttribute("targetUrl").toString();
		}
		return targetUrl;
	}

}